package de.jmda.gen.java.impl;

import static de.jmda.gen.java.naming.ImportManagerProvider.getImportManager;

import java.lang.annotation.Annotation;

import javax.lang.model.element.Name;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.validation.constraints.NotNull;

import de.jmda.gen.java.DeclaredElementGenerator;
import de.jmda.gen.java.DeclaredMethodGenerator;
import de.jmda.gen.java.MethodGenerator;
import de.jmda.gen.java.MethodModifiersGenerator;
import de.jmda.gen.java.ModifiersUtil.VisibilityModifier;

/**
 * @author roger.jmda@gmail.com
 */
public abstract class AbstractMethodGenerator
		extends AbstractDeclarationGenerator
		implements MethodGenerator
{
	private DeclaredMethodGenerator declaredMethodGenerator;

	public AbstractMethodGenerator()
  {
		this(null);
  }

	/**
	 * @param generator
	 */
	public AbstractMethodGenerator(
			@NotNull DeclaredMethodGenerator generator)
  {
	  super();

	  if (generator == null)
	  {
	  	generator = new DefaultDeclaredInstanceMethodGenerator();
	  }

	  setDeclaredMethodGenerator(generator);

	  setComponentSeparator(System.lineSeparator());
  }

	@Override
  public DeclaredMethodGenerator getDeclaredMethodGenerator()
  {
	  return declaredMethodGenerator;
  }

	@Override
  public void setDeclaredMethodGenerator(DeclaredMethodGenerator generator)
  {
		if (generator == null)
		{
			return;
		}
		
		this.declaredMethodGenerator = generator;
  }

	@Override
  public DeclaredElementGenerator getDeclaredElementGenerator()
  {
	  return getDeclaredMethodGenerator();
  }

	@Override
  public void addAnnotation(@NotNull Class<? extends Annotation> annotation)
  {
		demandAnnotationStatementsGenerator()
				.getAnnotationStatementGenerators()
				.add(new DefaultAnnotationStatementGenerator(annotation));
  }

	@Override
  public void setType(@NotNull TypeMirror type)
  {
		getDeclaredMethodGenerator().setTypeNameGenerator(
				new DefaultTypeNameGenerator(getImportManager().useType(type)));
  }

	@Override
  public void setType(@NotNull TypeElement type)
  {
		getDeclaredMethodGenerator().setTypeNameGenerator(
				new DefaultTypeNameGenerator(getImportManager().useType(type)));
  }

	@Override
  public void setType(@NotNull Class<?> type)
  {
		getDeclaredMethodGenerator().setTypeNameGenerator(
				new DefaultTypeNameGenerator(getImportManager().useType(type)));
  }

	@Override
  public void setType(@NotNull String typename)
  {
		getDeclaredMethodGenerator().setTypeNameGenerator(
				new DefaultTypeNameGenerator(typename));
  }

	@Override
  public void setTypeFrom(@NotNull VariableElement variableElement)
  {
		getDeclaredMethodGenerator().setTypeNameGenerator(
				new DefaultTypeNameGenerator(
						getImportManager().useTypeOf(variableElement)));
  }

	@Override
  public void addParameter(@NotNull Class<?> type, @NotNull String name)
  {
		getDeclaredMethodGenerator().add(
				new DefaultParameterGenerator(getImportManager().useType(type), name));
  }

	@Override
  public void addParameter(@NotNull TypeMirror type, @NotNull String name)
  {
		getDeclaredMethodGenerator().add(
				new DefaultParameterGenerator(getImportManager().useType(type), name));
  }

	@Override
  public void addParameter(@NotNull TypeElement type, @NotNull String name)
  {
		getDeclaredMethodGenerator().add(
				new DefaultParameterGenerator(getImportManager().useType(type), name));
  }

	@Override
  public void addParameter(@NotNull String type, @NotNull String name)
  {
		getDeclaredMethodGenerator().add(
				new DefaultParameterGenerator(getImportManager().useType(type), name));
  }

	@Override
  public void addParameterFrom(
      @NotNull VariableElement field, @NotNull String name)
  {
		getDeclaredMethodGenerator().add(
				new DefaultParameterGenerator(getImportManager().useTypeOf(field), name));
  }

	@Override
  public void addParameterFrom(
      @NotNull VariableElement field, @NotNull Name name)
  {
		addParameterFrom(field, name.toString());
  }

	@Override
  public void setMethodBody(String methodBody)
  {
		getDeclaredMethodGenerator().setMethodBody(methodBody);
  }

	@Override
  public void setName(@NotNull String methodName)
  {
		getDeclaredMethodGenerator().setMethodNameGenerator(
				new DefaultMethodNameGenerator(methodName));
  }

	@Override
  public void setName(@NotNull Name methodName)
  {
		setName(methodName.toString());
  }

	@Override
  public void setVisibility(VisibilityModifier modifier)
  {
		MethodModifiersGenerator modifiersGenerator =
				getDeclaredMethodGenerator().demandModifiersGenerator();
		
		if (modifier == VisibilityModifier.DEFAULT)
		{
			// do nothing
		}
		else if (modifier == VisibilityModifier.PRIVATE)
		{
			modifiersGenerator.setPrivate(true);
		}
		else if (modifier == VisibilityModifier.PROTECTED)
		{
			modifiersGenerator.setProtected(true);
		}
		else if (modifier == VisibilityModifier.PUBLIC)
		{
			modifiersGenerator.setPublic(true);
		}
  }
}